/**
 * C 语言版本
 */
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <unistd.h>
#include <string>
#include "thread_pool_c.h"
using namespace std;
//定义一个常量，在管理者线程中用到
const int NUMBER = 2;
//任务结构体定义
typedef struct Task{
    void(*function) (void* arg);
    void *arg;
}Task;
struct Thread_Pool{

    Task *TaskQ;//任务队列
    int queueCapacity; //容量
    int queueSize;// 当前队列任务数
    int queueFront;//队头，取数据
    int queueRear; //队尾，放数据

    pthread_t managerID;//管理者线程ID
    pthread_t *threadID;//工作的线程ID

    int min_num; //最小线程数
    int max_num; //最大线程数
    int live_num;//存活的线程数
    int busy_num;//工作的线程数
    int exit_num;//要销毁的线程数

    pthread_mutex_t mutexPool;//线程池的锁
    pthread_mutex_t mutexBusy;//锁busy_num

    pthread_cond_t not_FULL; //任务队列是不是满了
    pthread_cond_t not_Empty;//任务队列是不是空了

    int shutdown; //是不是要销毁线程，线程池是否关闭，销毁为1，不销毁为0
};

Thread_Pool *threadPoolCreate(int min,int max,int queue_size)
{

    auto *pool = (Thread_Pool*)malloc(sizeof(Thread_Pool));
    do
    {
        if(pool == NULL)
        {
            cout<<"malloc threadpool Failed..."<<endl;
            break;
        }
        pool->threadID = (pthread_t*)malloc(sizeof(pthread_t) * max);
        if(pool->threadID == NULL)
        {
            cout<<"malloc threadID Failed..."<<endl;
            break;
        }
        //初始化内存pool->threadID
        memset(pool->threadID,0,sizeof(pthread_t)*max);
        pool->min_num = min;
        pool->max_num = max;
        pool->live_num = min;
        pool->busy_num = 0;
        pool->exit_num = 0;

        if(pthread_mutex_init(&pool->mutexPool,NULL) !=0
           || pthread_mutex_init(&pool->mutexBusy,NULL) !=0
           || pthread_cond_init(&pool->not_FULL,NULL)!=0
           || pthread_cond_init(&pool->not_Empty,NULL)!=0)
        {
            cout<<"mutex or condition init Failed..."<<endl;
            break;
        }

        //初始化任务队列
        pool->TaskQ = (Task*) malloc(sizeof(Task) * queue_size);
        pool->queueCapacity = queue_size;
        pool->queueSize = 0;
        pool->queueFront = 0;
        pool->queueRear = 0;

        pool->shutdown =0;

        //创建管理者线程
        pthread_create(&pool->managerID,NULL,manager,pool);
        //创建工作线程
        for(int i=0;i<min;++i)
        {
            pthread_create(&pool->threadID[i],NULL,worker,pool);
            cout<<"create thread success..."<<endl;
        }
        return pool;
    }while (0);


    //释放资源
    //如果有，才释放，所以要判断
    if(pool && pool->threadID)
    {
        free(pool->threadID);
        cout<<"free success..."<<endl;
    }
    if(pool && pool->TaskQ)
    {
        free(pool->TaskQ);
        cout<<"free success..."<<endl;
    }
    if(pool)
    {
        free(pool);
        cout<<"free success..."<<endl;
    }


    return NULL;
}
void threadADD(Thread_Pool* pool,void(*func)(void*),void*arg)
{
    pthread_mutex_lock(&pool->mutexPool);
    while(pool->queueSize == pool->queueCapacity && !pool->shutdown)
    {
        //阻塞生产者线程
        pthread_cond_wait(&pool->not_FULL,&pool->mutexPool);
    }
    if(pool->shutdown)
    {
        pthread_mutex_unlock(&pool->mutexPool);
        return;
    }
    //添加任务
    pool->TaskQ[pool->queueRear].function = func;
    pool->TaskQ[pool->queueRear].arg = arg;
    pool->queueRear = (pool->queueRear+1) % pool->queueCapacity;
    pool->queueSize++;
    pthread_cond_signal(&pool->not_Empty);
    pthread_mutex_unlock(&pool->mutexPool);

}
void *worker(void *arg)
{
    auto *pool =(Thread_Pool*)arg;

    while(1)
    {
        pthread_mutex_lock(&pool->mutexPool);
        //判断当前任务队列是否为空
        //当前队列任务数为0，并且线程池没有关闭
        while(pool->queueSize ==0 && !pool->shutdown)
        {
            //阻塞工作线程
            pthread_cond_wait(&pool->not_Empty,&pool->mutexPool);
            //判断是不是要按销毁线程
            if(pool->exit_num > 0)
            {
                pool->exit_num--;
                if(pool->live_num > pool->min_num)
                {
                    pool->live_num--;
                    pthread_mutex_unlock(&pool->mutexPool);
                    threadExit(pool);
                }
            }

        }
        //判断线程池是否关闭了
        if(pool->shutdown)
        {
            pthread_mutex_unlock(&pool->mutexPool);
            threadExit(pool);
        }
        //从任务队列中取出一个任务
        Task task;
        task.function = pool->TaskQ[pool->queueFront].function;
        task.arg = pool->TaskQ[pool->queueFront].arg;
        //移动头结点
        pool->queueFront = (pool->queueFront+1) % pool->queueCapacity;
        pool->queueSize--;
        //唤醒生产者线程
        pthread_cond_signal(&pool->not_FULL);
        //解锁
        pthread_mutex_unlock(&pool->mutexPool);

        //取出任务后，执行任务
        cout<<"thread "<<pthread_self()<<"  start working ......"<<endl;
        //工作的线程+1
        pthread_mutex_lock(&pool->mutexBusy);
        pool->busy_num++;
        pthread_mutex_unlock(&pool->mutexBusy);
        //调用任务里的的任务函数
        task.function(task.arg);
        //传进来的是堆内存，用完要释放
        free(task.arg);
        task.arg =NULL;
        cout<<"thread "<<pthread_self()<<"  end working ......"<<endl;
        //工作的线程-1
        pthread_mutex_lock(&pool->mutexBusy);
        pool->busy_num--;
        pthread_mutex_unlock(&pool->mutexBusy);

    }
    return NULL;

}

void *manager(void *arg)
{
    //初始化线程池
    auto *pool =(Thread_Pool*)arg;
    while (!pool->shutdown)
    {
        //每隔3秒检测一次
        sleep(3);
        //取出线程池中的任务数量，及当前线程数量
        pthread_mutex_lock(&pool->mutexPool);
        int queueSize = pool->queueSize;
        int livenum = pool->live_num;
        pthread_mutex_unlock(&pool->mutexPool);

        //取出线程池中正在忙的线程数量
        pthread_mutex_lock(&pool->mutexBusy);
        int busynum = pool->busy_num;
        pthread_mutex_unlock(&pool->mutexBusy);

        //添加线程
        if(queueSize > livenum && livenum < pool->max_num)
        {
            pthread_mutex_lock(&pool->mutexPool);
            int counter = 0;
            for(int i=0;i < pool->max_num && counter < NUMBER &&pool->live_num < pool->max_num; ++i)
            {
                if(pool->threadID[i] ==0)
                {
                    pthread_create(&pool->threadID[i],NULL,worker,pool);
                    counter++;
                    pool->live_num++;
                }
            }
            pthread_mutex_unlock(&pool->mutexPool);
        }
        //销毁线程
        //判断条件
        if(busynum*2 < livenum && livenum > pool->min_num)
        {
            pthread_mutex_lock(&pool->mutexPool);
            pool->exit_num = NUMBER;
            pthread_mutex_unlock(&pool->mutexPool);
            //让线程自杀
            for(int i =0;i<NUMBER;++i)
            {
                //引导操作，引导到工作线程那里，唤醒阻塞到工作线程信号变量那的工作线程，用broadcast也可以
                pthread_cond_signal(&pool->not_Empty);
            }
        }
    }
    return NULL;
}

void threadExit(Thread_Pool* pool)
{
    pthread_t tid = pthread_self();
    for(int i = 0;i < pool->max_num; ++i)
    {
        if(pool->threadID[i] == tid)
        {
            pool->threadID[i] = 0;
            cout<<"threadExit() called "<<tid<<"  exiting ......"<<endl;
            break;
        }
        pthread_exit(NULL);
    }
}

int threadPoolDestroy(Thread_Pool* pool)
{
    //判断是否为空
    if(pool == NULL)
    {
        return -1;
    }
    //关闭线程池
    pool->shutdown = 1;
    //阻塞回收管理者线程
    pthread_join(pool->managerID,NULL);
    //唤醒阻塞的消费者线程
    for(int i=0;i<pool->max_num;++i)
    {
        pthread_cond_signal(&pool->not_Empty);
    }
    //释放堆内存
    if(pool->TaskQ)
    {
        free(pool->TaskQ);
    }
    if(pool->threadID)
    {
        free(pool->threadID);
    }
    //释放互斥锁和条件变量的资源
    pthread_mutex_destroy(&pool->mutexPool);
    pthread_mutex_destroy(&pool->mutexBusy);
    pthread_cond_destroy(&pool->not_Empty);
    pthread_cond_destroy(&pool->not_FULL);
    //释放线程池
    free(pool);
    pool=NULL;
    return 0;
}
int threadPoolBusyNum(Thread_Pool *pool)
{
    pthread_mutex_lock(&pool->mutexBusy);
    int busyNum = pool->busy_num;
    pthread_mutex_unlock(&pool->mutexBusy);
    return busyNum;
}
int threadPoolAliveNum(Thread_Pool *pool)
{
    pthread_mutex_lock(&pool->mutexPool);
    int aliveNum = pool->live_num;
    pthread_mutex_unlock(&pool->mutexPool);
    return aliveNum;
}
